<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>异步操作和Async函数</title>
</head>
<script src="./js/browser.js"></script>
<script type="text/babel">
    // setTimeout(function (args) {
    //     console.log('timeout')
    // },1000);
    //
    // setInterval(function (args) {
    //     console.log('setInterval')
    // },1000)

    console.log( "1" );
    setTimeout(function() {
        console.log( "2" )
    }, 0 );
    setTimeout(function() {
        console.log( "3" )
    }, 0 );
    setTimeout(function() {
        console.log( "4" )
    }, 0 );
    console.log( "5" );

    //1、5、2、3、4
    // 管setTimeout的time延迟时间为0，其中的function也会被放入一个队列中，等待下一个机会执行，
    // 当前的代码（指不需要加入队列中的程序）必须在该队列的程序完成之前完成，因此结果可能不与预期结果相同


    // 所有任务可以分成两种，一种是同步任务（synchronous），另一种是异步任务（asynchronous）。
    // 同步任务指的是，在主线程上排队执行的任务，只有前一个任务执行完毕，才能执行后一个任务；
    // 异步任务指的是，不进入主线程、而进入"任务队列"（task queue）的任务，只有等主线程任务执行完毕，"任务队列"开始通知主线程，请求执行任务，该任务才会进入主线程执行。

    //异步执行机制：
    // （1）所有同步任务都在主线程上执行，形成一个执行栈（execution context stack）。
    // （2）主线程之外，还存在一个"任务队列"（task queue）。只要异步任务有了运行结果，就在"任务队列"之中放置一个事件。
    // （3）一旦"执行栈"中的所有同步任务执行完毕，系统就会读取"任务队列"，看看里面有哪些事件。那些对应的异步任务，于是结束等待状态，进入执行栈，开始执行。

    //同步与异步
    // "同步模式"就是上一段的模式，后一个任务等待前一个任务结束，然后再执行，程序的执行顺序与任务的排列顺序是一致的、同步的；
    // "异步模式"则完全不同，每一个任务有一个或多个回调函数（callback），前一个任务结束后，不是执行后一个任务，而是执行回调函数，
    // 后一个任务则是不等前一个任务结束就执行，所以程序的执行顺序与任务的排列顺序是不一致的、异步的

    //回调函数
    //回调函数的优点是简单、容易理解和部署，缺点是不利于代码的阅读和维护，各个部分之间高度耦合（Coupling），流程会很混乱，而且每个任务只能指定一个回调函数。

    /*
			 * 异步编程对js语言太重要。js语言的执行环境是单线程的，如果没有异步编程，根本没法用。
			 *
			 * ES6以前，异步编程的方法，大概有四种：
			 *   回调函数  事件监听   发布/订阅  Promise对象
			 *
			 * ES6将js异步编程带入了一个新阶段，ES7的Async函数更是提出了异步编程的终极解决方案。
			 *
			 * 所谓异步，就是一个任务分成两段，先执行一段，然后转而执行其他任务，等做好了准备，再回头执行第二段。
			 * 这种不连续的执行，就叫异步。
			 * 相应的，连续的执行叫同步，由于是连续执行，所以要等待IO，这时候程序暂停，cpu浪费。
			 *
			 * 回调函数：
			 * js语言对异步编程的实现，就是回调函数。所谓回调函数，就是把任务的第二段单独写在一个函数里面。
			 * 等到重新执行这个任务的时候，就直接调用这个函数。
			 * 回调函数不多说，这里只说Node.js约定，回调函数的第一个参数是err，原因是执行分成两段，这两段之间抛出的
			 * 错误，程序无法捕捉，只能当做参数，传入第二段。
			 *
			 * Promise：
			 * 回调函数本身并没有问题，问题出在多个回调函数嵌套。如果多重嵌套，代码就横向发展，很快就乱成一团，这种
			 * 情况称为 回调函数噩梦。
			 * Promise就是为了解决回调函数噩梦的问题提出的。它不是新的语法功能，而是一种新的写法，允许将回调函数的嵌套，
			 * 改成链式调用。
			 *
			 * Promise 的写法只是回调函数的改进，使用then方法后，异步任务的两段执行看的更清楚了，除此之外，并无新意。
			 * Promise的最大问题是代码冗余，原来的任务被Promise包装了以下，不管什么操作，一眼看去都是then，原来的语义
			 * 变得很不清楚。
			 *
			 * 更好的写法...
			 * Generator函数
			 * 协程：传统的编程语言，早有异步编程解决方案。其中有一种叫做协程，意思就是多个线程互相协作，完成异步任务。
			 *    协程有点像函数，又有点像线程。运行流程大致如下：
			 *     第一步，协程A开始执行。
			 * 	       第二步，协程A执行到一半，进入暂停，执行权转到协程B。
			 *     第三步，（一段时间后）协程B交还执行权。
			 *     第四步，协程A恢复执行。
			 * 举例来说，读取文件的协程写法如下：
			 *   function* asyncJob(){
			 * 	  // 其他代码
			 *    var f = yield readFile(fileA);
			 *    //其他代码
			 * }
			 * 上面代码的奥妙在于其中的yield命令。它表示执行到此处，执行权交给其他协程。也就是说yield是异步两个阶段的分界线。
			 * 协程遇到yield命令会暂停，等到执行权返回，再从暂停的地方继续往后执行。它最大的优点是代码的写法
			 * 非常像同步操作，除了yield命令，几乎一模一样。
			 *
			 * Generator函数的概念
			 *  Generator函数是协程在ES6的实现，最大的特点就是可以交出函数的执行权（即暂停执行）。
			 *  整个Generator函数就是一个封装的异步任务，或者说是异步任务的容器。异步操作需要暂停的地方，都用yield语句注明。
			 *
			 *
			 * 异步任务的封装：
			 * var fetch = require("node-fetch");
			 * function *gen(){
			 * 	var url = 'https://api.github.com/users/github';
			 *  var result = yield fetch(url);
			 * console.log(result.bio)
			 * }
			 *
			 * 上面代码中，Generator函数封装了一个异步操作，该操作先读取一个远程接口，然后从json格式的数据解析信息。
			 * 执行这段代码的方法如下：
			 * var g = gen();
			 * var result = g.next();
			 * result.value.then(function(data){
			 * 	return data.json();
			 * }).then(function(data){
			 * 	g.next(data);
			 * })
			 *
			 * 虽然Generator函数将异步操作表示的很简洁，但是流程管理却不方便，（什么时候执行第一段，什么时候执行第二段）
			 */


    /**
     * async 函数就是 Generator 函数的语法糖。
     * 同 Generator 函数一样，async 函数返回一个 Promise 对象，可以使用 then 方法添加回调函数。当函数执行的时候，一旦遇到 await 就会先返回，等到触发的异步操作完成，再接着执行函数体内后面的语句。
     */

    // function Person(){
    //     this.age = 0;
    //
    //     setInterval(() => {
    //         this.age++; // |this| 正确地指向 p 实例
    //         console.log(this.age)
    //     }, 1000);
    // }
    //
    // let p = new Person();

</script>
<body>

</body>
</html>